package edu.ntu.cloudroid.model.policy;

import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

import javax.jdo.annotations.Inheritance;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;

import edu.ntu.cloudroid.model.IDs;
import edu.ntu.cloudroid.model.UserData;
import edu.ntu.cloudroid.xacml.builder.policy.AbstractPolicyBuilder;
import edu.ntu.cloudroid.xacml.builder.policy.SimpleFilteringBuilder;
import edu.ntu.cloudroid.xacml.obligation.ObligationHandle;
import edu.ntu.cloudroid.xacml.obligation.FilteringObligation;

@PersistenceCapable(detachable = "true")
@Inheritance
public class SimpleFiltering extends AbstractPrivacyPreference implements
		Serializable {
	private static final long serialVersionUID = 1L;
	public static final TimeZone DEFAULT_TIME_ZONE = TimeZone
			.getTimeZone("GMT+00");

	/* begin filtering */
	public static final int GEQUAL = 0;
	public static final int EQUAL = 1;
	public static final int LEQUAL = 2;
	public static final int TIMECOMP = 3;

	public static final int TIMECONSTRAINT = 0;
	public static final int VALUECONSTRAINT = 1;

	@Persistent
	int constraintType; // time or value-based
	@Persistent
	int conditionType; // <=, =, >=
	@Persistent
	String constraintValue; // time or value
	/* end filtering */

	@Persistent
	private int lowerTimeHour;

	@Persistent
	private int lowerTimeMinute;

	@Persistent
	private int upperTimeHour;

	@Persistent
	private int upperTimeMinute;

	@Override
	public AbstractPolicyBuilder getPolicyBuilder() {
		return new SimpleFilteringBuilder();
	}	

	@Override
	public void initializePreference(String[] values) throws Exception {
		int i = 0;
		this.constraintType = new Integer(values[i]).intValue();
		i++;
		this.conditionType = new Integer(values[i]).intValue();
		i++;

		if (this.constraintType == TIMECONSTRAINT) {
			// time constraint
			this.lowerTimeHour = new Integer(values[i]).intValue();
			i++;
			this.lowerTimeMinute = new Integer(values[i]).intValue();
			i++;

			this.upperTimeHour = new Integer(values[i]).intValue();
			i++;
			this.upperTimeMinute = new Integer(values[i]).intValue();
			i++;
		} else {
			// column index
			this.setDataColumnIndex(new Integer(values[i]).intValue());
			i++;
			// value constraint
			this.constraintValue = values[i];
			i++;
		}

		// if the policy will only return the latest data
		this.latestDataOnly = new Boolean(values[i]).booleanValue();
		i++;
	}

	public int getConstraintType() {
		return constraintType;
	}

	public int getConditionType() {
		return conditionType;
	}

	public String getConstraintValue() {
		return constraintValue;
	}

	public Date getLowerTime() {
		return getTime(lowerTimeHour, lowerTimeMinute);
	}

	public void setLowerTime(int hour, int minute) {
		this.lowerTimeHour = hour;
		this.lowerTimeMinute = minute;
	}

	public Date getUpperTime() {
		return getTime(upperTimeHour, upperTimeMinute);
	}

	public void setUpperTime(int hour, int minute) {
		this.upperTimeHour = hour;
		this.upperTimeMinute = minute;
	}

	public int getLowerTimeHour() {
		return this.lowerTimeHour;
	}

	public void setLowerTimeHour(int lowerTimeHour) {
		this.lowerTimeHour = lowerTimeHour;
	}

	public int getLowerTimeMinute() {
		return this.lowerTimeMinute;
	}

	public void setLowerTimeMinute(int lowerTimeMinute) {
		this.lowerTimeMinute = lowerTimeMinute;
	}

	public int getUpperTimeHour() {
		return this.upperTimeHour;
	}

	public void setUpperTimeHour(int upperTimeHour) {
		this.upperTimeHour = upperTimeHour;
	}

	public int getUpperTimeMinute() {
		return this.upperTimeMinute;
	}

	public void setUpperTimeMinute(int upperTimeMinute) {
		this.upperTimeMinute = upperTimeMinute;
	}

	private static Date getTime(int hour, int minute) {
		// Normalize date to epoch
		// TODO: verify date normalization
		// TODO: verify validation for hour and minute
		Calendar timeSetterCalendar = Calendar.getInstance();
		timeSetterCalendar.setTimeInMillis(0);
		timeSetterCalendar.set(Calendar.HOUR_OF_DAY, hour);
		timeSetterCalendar.set(Calendar.MINUTE, minute);
		return timeSetterCalendar.getTime();
	}

	@Override
	public UserData getMetaData(Object param) throws Exception {
		//null param means default policy, otherwise it contains the groupname
		String type="";
		if (param==null)
			type = type+AbstractPrivacyPreference.ISALL;
		else
			type = type+AbstractPrivacyPreference.ISGROUP+","+param.toString();
		
		String s = this.getUserName()+","+IDs.PolicyID.SimpleFiltering.ordinal() + ","
				+ type + "," + this.constraintType
				+ "," + this.conditionType;
		if (this.constraintType == AbstractPrivacyPreference.TIMECONSTRAINT)
			s = s + "," + this.lowerTimeHour + "," + this.lowerTimeMinute + ","
					+ this.upperTimeHour + "," + this.upperTimeMinute + ","
					+ this.isLatestDataOnly();
		else
			s = s+","+this.getDataColumnIndex()+","+this.constraintValue+","+this.isLatestDataOnly();
		return new PolicyInfo(this.getUserName(), s.split(","));
	}
}
